/*
何为智能指针？能不让你写出 ****s 形式的解引用，我认为就是智能: )，
智能指针的名称来源，主要就在于它实现了 Deref 和 Drop 特征，这两个特征可以智能地帮助我们节省使用上的负担：
    Deref 可以让智能指针像引用那样工作，这样你就可以写出同时支持智能指针和引用的代码，例如 *T
    Drop 允许你指定智能指针超出作用域后自动执行的代码，例如做一些数据清除等收尾工作
*/
#[cfg(test)]
mod box_deref {
    use std::fmt::{Display, Formatter};
    use std::ops::Deref;

    #[derive(Debug)]
    struct Person {
        name: String,
        age: u8,
    }

    impl Person {
        fn new(name: String, age: u8) -> Self {
            Person { name, age }
        }
        fn display(self: &mut Person, age: u8) {
            // &&mut Person 跟 Person 匹配
            let Person { name, age } = &self;
        }
    }

    #[test]
    fn main() {
        let x = 5;
        let y = &x;
        println!("{:?} {:?} {:?}", y, *y, &x);
        let vox = Box::new(1); // 类似普通引用
        let sum = *vox + 1;
        println!("{}", sum)
    }

    struct MyBox<T: Display>(T);

    impl<T: Display> Display for MyBox<T> {
        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
            write!(f, "{}", self.0)
        }
    }

    impl<T: Display> MyBox<T> {
        fn new(x: T) -> MyBox<T> {
            MyBox(x)
        }
    }

    impl<T: Display> Deref for MyBox<T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            println!("Deref::{}", &self.0);
            &self.0
        }
    }

    #[test]
    fn custom_box() {
        let my_box = MyBox::new(1);
        println!("{}", my_box);
        println!("{}", *my_box); //自动调用 Deref
        println!("{}", *(my_box.deref())) //* 不会无限递归替换，从 *y 到 *(y.deref()) 只会发生一次
    }

    fn display(s: &str) {
        println!("{}", s);
    }

    #[test]
    fn shadow_deref() {
        // String 实现了 Deref 特征，可以在需要时自动被转换为 &str 类型
        // &s 是一个 &String 类型，当它被传给 display 函数时，自动通过 Deref 转换成了 &str
        // 必须使用 &s 的方式来触发 Deref(仅引用类型的实参才会触发自动解引用)
        let s = String::from("hello world");
        display(&s);

        // 但是 Deref 并不是没有缺点，缺点就是：如果你不知道某个类型是否实现了 Deref 特征，
        // 那么在看到某段代码时，并不能在第一时间反应过来该代码发生了隐式的 Deref 转换
        //  自动连续解引用
        let ok = MyBox::new(String::from("hello world"));
        display(&ok);
    }

    #[test]
    fn value_deref() {
        let s = MyBox::new(String::from("hello, world"));
        let s1: &str = &s;
        let s2: String = s.to_string();

        // 对于 s1，我们通过两次 Deref 将 &str 类型的值赋给了它（赋值操作需要手动解引用）；
        // 而对于 s2，我们在其上直接调用方法 to_string，
        // 实际上 MyBox 根本没有没有实现该方法，能调用 to_string，
        // 完全是因为编译器对 MyBox 应用了 Deref 的结果（方法调用会自动解引用）
    }
}

// 引用归一化

/*
Rust 编译器实际上只能对 &v 形式的引用进行解引用操作，那么问题来了，如果是一个智能指针或者 &&&&v 类型的呢？ 该如何对这两个进行解引用？
    答案是：Rust 会在解引用时自动把智能指针和 &&&&v 做引用归一化操作，转换成 &v 形式，最终再对 &v 进行解引用：
        把智能指针（比如在库中定义的，Box、Rc、Arc、Cow 等）从结构体脱壳为内部的引用类型，也就是转成结构体内部的 &v
        把多重&，例如 &&&&&&&v，归一成 &v
*/
#[cfg(test)]
mod deref {
    use std::rc::Rc;

    fn foo(s: &str) {}

    #[test]
    fn asd() {
        // 由于 String 实现了 Deref<Target=str>
        let owned = "Hello".to_string();
        // 因此下面的函数可以正常运行：
        foo(&owned);

        // String 实现了 Deref<Target=str>
        let owned = "Hello".to_string();
        // 且 Rc 智能指针可以被自动脱壳为内部的 `owned` 引用： &String ，然后 &String 再自动解引用为 &str
        let counted = Rc::new(owned);
        // 因此下面的函数可以正常运行:
        foo(&counted);
    }

    struct Foo;

    impl Foo {
        fn foo(&self) {
            println!("Foo");
        }
    }

    #[test]
    fn deref_struct() {
        let f = &&Foo;

        f.foo();
        (&f).foo();
        (&&f).foo();
        (&&&&&&&&f).foo();
    }
}

/*

 Rust 还支持将一个可变的引用转换成另一个可变的引用以及将一个可变引用转换成不可变的引用，规则如下：

        当 T: Deref<Target=U>，可以将 &T 转换成 &U，也就是我们之前看到的例子
            将 &mut T 类型通过 DerefMut 特征的方法转换为 &mut U 类型
        当 T: DerefMut<Target=U>，可以将 &mut T 转换成 &mut U
        当 T: Deref<Target=U>，可以将 &mut T 转换成 &U
Rust 可以把可变引用隐式的转换成不可变引用，但反之则不行

*/
#[cfg(test)]
mod deref_trans {
    struct MyBox<T> {
        v: T,
    }

    impl<T> MyBox<T> {
        fn new(x: T) -> MyBox<T> {
            MyBox { v: x }
        }
    }

    use std::ops::Deref;

    impl<T> Deref for MyBox<T> {
        type Target = T;

        fn deref(&self) -> &Self::Target {
            &self.v
        }
    }

    use std::ops::DerefMut;

    // 要实现 DerefMut 必须要先实现 Deref 特征：pub trait DerefMut: Deref
    impl<T> DerefMut for MyBox<T> {
        fn deref_mut(&mut self) -> &mut Self::Target {
            &mut self.v
        }
    }

    #[test]
    fn main() {
        let mut s = MyBox::new(String::from("hello, "));
        // &mut MyBox<String> 转换为 &mut String
        display(&mut s)
    }

    fn display(s: &mut String) {
        s.push_str("world");
        println!("{}", s);
    }
}
